# The code in this file generates Figures 4 and 5 using datasets made by assembling replication files from each study used in the meta-analysis.
# Because these data are the property of the respective authors of these studies, these files are not included in this replication file.

# FIGURE 4 ----

all_conjoints <- read_csvy("all_conjoints.csv", stringsAsFactors = T) %>% 
  filter(poc=="black"&paste(resprace, respparty) %in% c("White Democrat", "Black Democrat", "White Republican")) # subset to 3 groups and choices between white and Black candidates
all_conjoints$pub <- as.character(all_conjoints$pub)
all_conjoints$platform <- as.character(all_conjoints$platform)

figdat <- all_conjoints %>%
  filter(race=="black") %>%
  mutate(yearnum = (year - 1988),
         yearnum2 = (year - 2012),
         period = case_when(year < 2012 ~ "Pre-2012",
                            year < 2017 ~ "2012-2016",
                            year < 2024 ~ "2017-2023"),
         period = factor(period, levels = c("Pre-2012", "2012-2016", "2017-2023"), ordered = T))

fit_whitedems <- lmer(chosen_candidate ~ year + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Democrat",])
dat_whitedems <- make_predictions(fit_whitedems, pred = "year") %>% mutate(group = "White Democrats")
fit_whitereps <- lmer(chosen_candidate ~ year + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Republican",])
dat_whitereps <- make_predictions(fit_whitereps, pred = "year") %>% mutate(group = "White Republicans")
fit_blackdems <- lmer(chosen_candidate ~ year + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="Black Democrat",])
dat_blackdems <- make_predictions(fit_blackdems, pred = "year") %>% mutate(group = "Black Democrats")

by_project_out <- read.csv("MMs_wvb_respracerespparty_main3_weighted.csv") %>%
  mutate(group = case_when(type=="White Democratic respondents"~"White Democrats",
                           type=="White Republican respondents"~"White Republicans",
                           type=="Black Democratic respondents"~"Black Democrats")) %>%
  select(-X)

res <- bind_rows(dat_whitedems, dat_whitereps, dat_blackdems) %>% 
  select(-pub) %>% 
  distinct() %>%
  full_join(by_project_out)

ggplot(res, aes(x = year)) +
  geom_hline(yintercept = 0.5, linetype = "dashed", color = "darkgrey") +
  geom_ribbon(data = res[!is.na(res$ymin),], aes(x = year, ymin = ymin, ymax = ymax), alpha = 0.25) + 
  geom_path(aes(y = chosen_candidate)) +
  geom_point(aes(y = estimate, size = weighted.n), shape = 1) +
  theme_bw() +
  theme(text = element_text(family = "serif"),
        panel.grid = element_blank(),
        legend.position = "none") +
  xlab("") +
  ylab("Estimated proportion selecting Black candidate") +
  facet_grid(~group)

# FIGURE 5 ----

figdat <- read.csv("meta_by_period.csv")

whitedems <- as.data.frame(coef(summary(lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub) + 0, weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Democrat",])))) %>% 
  tibble::rownames_to_column("period") %>%
  mutate(group = "White Democrats")

blackdems <- as.data.frame(coef(summary(lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub) + 0, weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="Black Democrat",])))) %>% 
  tibble::rownames_to_column("period") %>%
  mutate(group = "Black Democrats")

whitereps <- as.data.frame(coef(summary(lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub) + 0, weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Republican",])))) %>% 
  tibble::rownames_to_column("period") %>%
  mutate(group = "White Republicans")

rbind(whitedems, blackdems, whitereps) %>%
  mutate(period = gsub("factor\\(period, ordered = F\\)", "", period),
         period = factor(period, levels = c("Pre-2012", "2012-2016", "2017-2023"), ordered = T),
         std.error = as.numeric(`Std. Error`),
         estimate = as.numeric(Estimate),
         upper = estimate + 1.96 * std.error,
         lower = estimate - 1.96 * std.error) %>%
  ggplot(aes(x = period, y = estimate)) +
  geom_hline(yintercept = 0.5, linetype = 'dashed', color = 'darkgrey') +
  geom_point() +
  geom_errorbar(aes(ymin=lower, ymax=upper), width = 0) +
  facet_wrap(~group) +
  theme_bw() +
  theme(text = element_text(family = "serif"),
        panel.grid = element_blank(),
        legend.position = "none") +
  xlab("") +
  ylab("Estimated proportion selecting Black candidate") +
  geom_bracket(data = data.frame(group = "White Democrats"), xmin = "Pre-2012", xmax = "2012-2016", y.position = 0.542, label = "p < 0.001", tip.length = c(0.02, 0.02), family = "serif") +
  geom_bracket(data = data.frame(group = "White Democrats"), xmin = "2012-2016", xmax = "2017-2023",
               y.position = 0.57, label = "p = 0.021", tip.length = c(0.02, 0.02), family = "serif")

# APPENDIX FIGURE B1 ----

by_project_out <- read.csv("MMs_wvb_respracerespparty_main3_weighted.csv")
dwplot(by_project_out,
       vars_order = c("1988 LA Times",
                      "1989 LA Times", 
                      "2004 KN", 
                      "2012 GfK", 
                      "2012 MTurk", 
                      "2013 GFK", 
                      "2015 YouGov", 
                      "2016 Facebook", 
                      "2016 MTurk", 
                      "2016 MTurk 2", 
                      "2016 Qualtrics", 
                      "2016 Research Now/SSI",
                      "2016 SSI", 
                      "2016 SSI 2", 
                      "2016 SSI 3", 
                      "2016 YouGov", 
                      "2016 YouGov 2", 
                      "2016 YouGov 3", 
                      "2017 MTurk", 
                      "2018 Cint", 
                      "2018 Lucid",
                      "2018 Lucid 2", 
                      "2018 YouGov", 
                      "2019 Fuqua Behavioral Lab", 
                      "2019 MTurk", 
                      "2019 Qualtrics", 
                      "2019 YouGov", 
                      "2019 YouGov 2", 
                      "2019 YouGov 3", 
                      "2020 Lucid", 
                      "2020 MTurk",
                      "2020 YouGov", 
                      "2020 YouGov 2",
                      "2020 YouGov 3", 
                      "2021 Lucid", 
                      "2022 Lucid", 
                      "2022 Lucid 2",
                      "2023 Lucid", 
                      "2023 Lucid 2", 
                      "2023 Lucid 3", 
                      "2023 CA voter file",
                      "2023 Lucid 4"),
       vline = geom_vline(xintercept = 0.5, color = "darkgrey", linetype = "dashed")) +
  theme_bw() +
  theme(legend.position = "none",
        text = element_text(family = "serif"),
        panel.grid = element_blank(),
        strip.placement = "outside",
        strip.background = element_rect(fill = "white"),
        strip.text.y = element_text(face = "bold")) +
  facet_wrap(~type) +
  scale_color_manual(values = c("black", "black")) +
  geom_rect(data = data.frame(type = "White Democratic respondents"), aes(xmin = 0.42, xmax = 0.72, ymin = 0.6, ymax = 6.2), color = "darkgrey", alpha = 0) +
  geom_rect(data = data.frame(type = "Black Democratic respondents"), aes(xmin = 0.49, xmax = 0.79, ymin = 0.7, ymax = 2.5), color = "darkgrey", alpha = 0) +
  geom_rect(data = data.frame(type = "White Republican respondents"), aes(xmin = 0.41, xmax = 0.60, ymin = 1.7, ymax = 2.5), color = "darkgrey", alpha = 0) +
  geom_text(data = data.frame(type = "White Democratic respondents"), x = 0.4, y = 0.6, label = "Original studies", angle = 90, family = "serif", hjust = 0, color = "grey30", size = 3) +
  xlab("Marginal means for Black candidates with white opponents")

# APPENDIX TABLE B4 ----
figdat <- read.csv("meta_by_period.csv")


modelsummary(
  list(
    "White Democratic participants" = list(
      "1988-2023" = lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Democrat",]),
      "1988-2023 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Democrat",]),
      "2012-2023 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Democrat"&figdat$year>2010,]),
      "2012-2022 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Democrat"&figdat$year>2010&!grepl("Mikkelborg", figdat$pub),])
    ),
    "Black Democratic participants" = list(
      "1988-2023" = lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="Black Democrat",]),
      "1988-2023 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="Black Democrat",]),
      "2012-2023 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="Black Democrat"&figdat$year>2010,]),
      "2012-2022 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="Black Democrat"&figdat$year>2010&!grepl("Mikkelborg", figdat$pub),])
    ),
    "White Republican participants" = list(
      "1988-2023" = lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Republican",]),
      "1988-2023 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Republican",]),
      "2012-2023 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Republican"&figdat$year>2010,]),
      "2012-2022 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Republican"&figdat$year>2010&!grepl("Mikkelborg", figdat$pub),])
    ),
    "All white participants" = list(
      "1988-2023" = lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = white_weight, all_conjoints_allwhites),
      "1988-2023 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = white_weight, all_conjoints_allwhites),
      "2012-2023 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = white_weight, all_conjoints_allwhites[all_conjoints_allwhites$year>2010,]),
      "2012-2022 by period" = lme4::lmer(chosen_candidate ~ factor(period, ordered = F) + (1|pub), weights = white_weight, all_conjoints_allwhites[all_conjoints_allwhites$year>2010&!grepl("Mikkelborg", all_conjoints_allwhites$pub),]))
  ),
  shape = "rbind",
  stars = T,
  escape = F,
  estimate = "{estimate}{stars} ({std.error})",
  statistic = NULL,
  gof_map = c("nobs", "r.squared"),
  title = "Estimated proportion of study participants selecting Black candidates over white opponents across 42 candidate choice experiments, 1989-2023.",
  coef_map = list("(Intercept)" = "Intercept",
                  "yearnum" = "Year",
                  "yearnum2" = "Year",
                  "factor(period, ordered = F)2012-2016" = "2012-2016",
                  "factor(period, ordered = F)2017-2023" = "2017-later"),
  output = "kableExtra"
) %>%
  add_header_above(c(" " = 1, "DV: Estimated proportion selecting Black candidate" = 4)) %>%
  kable_styling(font_size = 8.5) %>%
  #column_spec(2:5, width = "2.5cm") %>%
  footnote("This table presents the results of linear regression models with random effects by study. The dependent variable is the estimated proportion of participants in the studies being re-analyzed who selected a Black candidate over a white opponent. The explanatory variable is the year the study was conducted; the unit is one year. The reference year in the first column is 1988, the year of the earliest study in the dataset. The reference category in the second column is studies conducted between 1988 and 2012. The reference category in the third and fourth columns is studies conducted between 2012 and 2016. All models include study random effects. Models in the first three sections include weights for demographic representativeness on the basis of gender, age, and region within race-party-year. Models in the final section include study random effects and weights for demographic representativeness on the basis of gender, age, region, and partisanship within year.", threeparttable = T)

# APPENDIX TABLE B5 ----

beta_whitedems <- summary(lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Democrat",]))$coefficients[2,1]
se_whitedems <- summary(lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Democrat",]))$coefficients[2,2]

beta_blackdems <- summary(lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="Black Democrat",]))$coefficients[2,1]
se_blackdems <- summary(lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="Black Democrat",]))$coefficients[2,2]

beta_whitereps <- summary(lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Republican",]))$coefficients[2,1]
se_whitereps <- summary(lme4::lmer(chosen_candidate ~ yearnum + (1|pub), weights = weight2, figdat[paste(figdat$resprace, figdat$respparty)=="White Republican",]))$coefficients[2,2]

z.test.white.by.party <- (beta_whitedems - beta_whitereps) / sqrt(se_whitedems^2 + se_whitereps^2)
pval.white.by.party <- round(2 * pnorm(z.test.white.by.party, lower.tail = FALSE), 3)
z.test.dem.by.race <- (beta_whitedems - beta_blackdems) / sqrt(se_whitedems^2 + se_blackdems^2)
pval.dem.by.race <- round(2 * pnorm(z.test.dem.by.race, lower.tail = FALSE), 3)

names <- c("White Democrats vs. white Republicans", "White Democrats vs. Black Democrats")

res <- cbind(names, c(paste(round(z.test.white.by.party, 3), " (p = ", pval.white.by.party, ")", sep = ""),
                      paste(round(z.test.dem.by.race, 3), " (p = ", pval.dem.by.race, ")", sep = "")))

kable(res,
      booktabs = T, 
      caption = "Z-tests for meta-analysis results by group", 
      escape = F, 
      col.names = c("Groups", "Z-score (p-value)"))